package net.sk.china.front.strategy;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.model.user.User;
import net.sk.china.common.model.user.UserToken;
import net.sk.china.common.utils.DateUtil;
import net.sk.china.common.utils.TalkUtil;
import net.sk.china.front.constants.Constants;
import net.sk.china.front.dao.user.UserDao;
import net.sk.china.front.request.LoginRequest;
import net.sk.china.front.response.LoginResponse;
import net.sk.china.front.response.WeChatMiniAuthorizeResponse;
import net.sk.china.front.service.wechat.WechatService;
import net.sk.china.front.service.system.SystemConfigService;
import net.sk.china.front.service.user.UserService;
import net.sk.china.front.service.user.UserTokenService;
import net.sk.china.front.utils.WxUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;

/**
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/4 15:10
 * // +----------------------------------------------------------------------
 */
@Component
public class RoutineService implements UserInterface {

    private static final Logger logger = LoggerFactory.getLogger(RoutineService.class);

    @Resource
    private UserDao userDao;

    private final SystemConfigService systemConfigService;

    private final WechatService wechatService;

    private final UserService userService;

    private final UserTokenService userTokenService;

    private final TransactionTemplate transactionTemplate;

    public RoutineService(SystemConfigService systemConfigService, WechatService wechatService, UserService userService, UserTokenService userTokenService, TransactionTemplate transactionTemplate) {
        this.systemConfigService = systemConfigService;
        this.wechatService = wechatService;
        this.userService = userService;
        this.userTokenService = userTokenService;
        this.transactionTemplate = transactionTemplate;
    }

    /**
     * 微信小程序登录
     * @param request 请求对象
     * @param ip 客户端IP
     * @return {@code LoginResponse}
     */
    @Override
    public LoginResponse login(LoginRequest request, String ip) {
        if (StrUtil.isBlank(request.getCode())) {
            throw new TalkException("code码不能为空");
        }
        if (StrUtil.isBlank(request.getIv())) {
            throw new TalkException("iv不能为空");
        }
        if (StrUtil.isBlank(request.getEncryptedData())) {
            throw new TalkException("encryptedData不能为空");
        }
        // 获取小程序appId
        String programAppId = systemConfigService.getValueByKey(Constants.WECHAT_MINI_APPID);
        if (StrUtil.isBlank(programAppId)) {
            throw new TalkException("微信小程序还未配置appId");
        }

        WeChatMiniAuthorizeResponse response = wechatService.miniAuthCode(request.getCode());
        String decrypt = WxUtil.decrypt(programAppId, request.getEncryptedData(), response.getSessionKey(), request.getIv());
        if (StrUtil.isBlank(decrypt)) {
            throw new TalkException("微信小程序获取手机号解密失败");
        }

        JSONObject jsonObject = JSONObject.parseObject(decrypt);
        String phone = jsonObject.getString("purePhoneNumber");
        if (StrUtil.isBlank(phone)) {
            throw new TalkException("获取微信小程序无效的的手机号");
        }

        // 此字段用来判断用户是否注册
        boolean isNew = true;

        User user = userService.getByAccount(phone);
        if (ObjectUtil.isNull(user)) {
            user = new User();
            user.setPhone(phone);
            user.setAccount(phone);
            user.setCreateTime(DateUtil.getNowTime());
            user.setPwd(TalkUtil.createPwd(phone));
            user.setAddIp(ip);
            user.setUserType(Constants.USER_LOGIN_TYPE_PROGRAM);
            user.setAvatar(request.getAvatar());
            user.setNickname(request.getNickName());
        } else {
            // 已有账户，关联之前的账户即可
            if (user.getStatus().equals(Constants.NUM_ZERO)) {
                throw new TalkException("当前账户已禁用，请联系平台客服人员！");
            }
            isNew = false;
        }

        user.setUnionId(response.getUnionId());
        user.setLoginType(Constants.USER_LOGIN_TYPE_PROGRAM);
        user.setLastIp(ip);
        user.setLastLoginTime(DateUtil.getNowTime());

        // 重新赋值数据
        User newUser = user;
        boolean lastIsNew = isNew;

        LoginResponse loginResponse = new LoginResponse();

        // user、userToken在同一个库中并且在同一个微服务下，可用TransactionTemplate
        Boolean execute = transactionTemplate.execute(e -> {
            if (lastIsNew) {  // 新用户
                userDao.insert(newUser);
                // 绑定 userToken
                userTokenService.bind(response.getOpenId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM, newUser.getUid());
                loginResponse.setType("register");
            } else {  // 已经注册（通过其他客户端注册）
                // 检测 userToken 是否存在的依据
                UserToken userToken = userTokenService.getByOpenidAndType(response.getOpenId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM);
                if (ObjectUtil.isNull(userToken)) {
                    userTokenService.bind(response.getOpenId(), Constants.THIRD_LOGIN_TOKEN_TYPE_PROGRAM, newUser.getUid());
                }
                userDao.updateById(newUser);
                loginResponse.setType("login");
            }
            return Boolean.TRUE;
        });
        if (ObjectUtil.isNull(execute) || !execute) { logger.error(StrUtil.format("微信小程序一键授权登录失败，decrypt={}，response={}", decrypt, JSON.toJSONString(response))); }


        // 生成验证的token，很重要
        try {
            String token = userService.createToken(newUser.getUid());
            loginResponse.setToken(token);
        } catch (Exception e) {
            logger.error(StrUtil.format("生成用户Token失败：", e.getMessage()));
        }

        return loginResponse;
    }
}
